package epoch.game.core.distr;

import java.io.IOException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import epoch.game.core.buffer.IBuffer;
import epoch.game.core.distr.INodeChannel;
import epoch.game.core.distr.Node;
import epoch.game.core.distr.NodeChannelUtil;
import epoch.game.core.distr.NodeRegisterMessage;
import epoch.game.core.distr.NodeType;
import epoch.game.core.distr.RemoteNode;
import epoch.game.core.distr.config.DConfig;
import epoch.game.core.message.IMessage;
import epoch.game.core.message.SysMessageIds;
import epoch.game.core.serialize.StreamReader;
import epoch.game.core.server.ISession;

public class NodeConnectChannel implements INodeChannel {
	private static Logger logger = LogManager.getLogger(NodeChannel.class);
	
	private RemoteNode remoteNode;
	
	public NodeConnectChannel(RemoteNode remoteNode) {
		this.remoteNode = remoteNode;
	}
	

	private void handleReg(ISession session, IBuffer buffer) {
		NodeRegisterMessage msg = new NodeRegisterMessage();
		StreamReader reader = new StreamReader(buffer);
		try {
			msg.readFrom(reader);
		} catch (IOException e) {
		}

		if(!DConfig.NODE_SECRET_KEY.equals(msg.getSecretKey())){
			logger.error("Node register failed: secretKey error: {}", msg.getSecretKey());
			session.close();
			return;
		}
		int fromNodeId = msg.getNodeId();
		if (fromNodeId != remoteNode.getId()) {
			logger.error("Node register failed: nodeInfo error: recv {}, expect {}", 
					fromNodeId, remoteNode.getId());
			session.close();
			return;
		}
		remoteNode.setRegistered(true);
		session.setAttribute(NodeChannel.node_id, fromNodeId);
	}
	
	@Override
	public void onMessageReceived(ISession session, byte[] data) {
		try {
			IBuffer buffer = IBuffer.wrap(data);
			short msgId = buffer.readShort();
			if (!remoteNode.isRegistered()) {
				if (msgId == SysMessageIds.node_register) {
					handleReg(session, buffer);
				}
			} else {
				Node node = remoteNode.getLocalNode();
				if (msgId < 0) {
					NodeChannelUtil.handleRpc(node, session, msgId, buffer);
				} else {
					Integer fromNodeId = session.getAttribute(NodeChannel.node_id);
					if (fromNodeId != null) {
						RemoteNode remoteNode = node.getRemoteNode(fromNodeId);
						if (remoteNode != null) {
							NodeType fromNodeType = remoteNode.getType();
							IMessage iMessage = node.getHandler().newMessage(msgId, buffer);
							if (iMessage != null) {
								node.getHandler().onNodeMessageReveived(iMessage, fromNodeType);
							}
						}
					}
				}
			}
		} catch (Exception ex) {
			logger.error("处理收到的消息出错！"+ex, ex);
		}
	}

	@Override
	public void onSessionClosed(ISession session) {
		logger.info("Node session closed: {}", remoteNode.getTag());
		remoteNode.delSession(session);
		remoteNode.getLocalNode().getHandler().onNodeSessionClosed(session);
	}

	@Override
	public void onSessionCreated(ISession session) {
		logger.info("Node session created: {}", remoteNode.getTag());
		remoteNode.setSession(session);
		remoteNode.getLocalNode().getHandler().onNodeSessionCreated(session);
	}

	@Override
	public void onSessionOpened(ISession session) {
		logger.info("Node send register to: {}", remoteNode.getTag());
		Node node = remoteNode.getLocalNode();
		NodeChannelUtil.sendRegMsg(node, session);
	}

	@Override
	public void onSessionIdle(ISession session) {
		remoteNode.getLocalNode().getHandler().onNodeSessionIdle(session);
	}

	@Override
	public void onExceptionCaught(ISession session, Throwable throwable) {
		remoteNode.getLocalNode().getHandler().onNodeExceptionCaught(session,throwable);
	}

	@Override
	public void onMessageSent(ISession session, Object message) {
		remoteNode.getLocalNode().getHandler().onNodeMessageSent(session, message);
	}
}
